﻿using InParkRedemptionAPI.Controllers;
using InParkRedemptionAPI.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RapidSalesAdminPortalAPI.DataAccess;
using RapidSalesAdminPortalAPI.Models;
using WebAPI.Common;
using WebAPI.Common.Attributes;
using WebAPI.Controllers;
using WebAPI.Models;
using WebAPI.Util;

namespace RapidSalesAdminPortalAPI.Controllers
{
    //[Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class FrIpMasterDatumController : ParentController
    {
        private readonly RS_AdmPortalContext _context;
        private readonly IConfiguration _configuration;
        private readonly ILogUtility _logUtility;
        private readonly ILogger _logger;
        private readonly IDataProtectorUtility _dataProtectorUntility;
        public FrIpMasterDatumController(RS_AdmPortalContext context, IConfiguration configuration, ILogUtility logUtility, ILogger<FrIpMasterDatumController> logger, IDataProtectorUtility dataProtectorUntility)
        {
            _context = context;
            _configuration = configuration;
            _logUtility = logUtility; // sample code for DI of common utility class
            _logger = logger;
            _dataProtectorUntility = dataProtectorUntility;
        }

        [HttpPost("MasterDataSystemList")]
        public async Task<ActionResult<ResultMsg>> MasterDataSystemList(SystemListRequest requestModel)
        {
            var resultMsg = new ResultMsg();
            IQueryable<FrIpMasterDatum> paComont = _context.FrIpMasterData.Where(x => string.IsNullOrWhiteSpace(x.ParentCode) && x.Enable).AsQueryable();
            if (!string.IsNullOrWhiteSpace(requestModel.Description))
                paComont = paComont.Where(x => x.Description.Contains(requestModel.Description));
            if (!string.IsNullOrEmpty(requestModel.OptionSetGroup))
                paComont = paComont.Where(x => x.OptionSetGroup.Contains(requestModel.OptionSetGroup));
            var paData = paComont.ToList().Select(x => new MasterDataLisResponse()
            {
                Id = x.Id,
                Code = x.Code,
                Name = x.Name,
                Value = x.Value,
                Description = x.Description,
                Enable = x.Enable,
                OptionSetGroup = x.OptionSetGroup,
                
            }).AsQueryable();

            if (!string.IsNullOrWhiteSpace(requestModel.Field) && paComont.Count() > 0)
                paData = DBHelper.DataSorting(paData, requestModel.Field, requestModel.Order);
            else
                paData = DBHelper.DataSorting(paData, "CreateDate", "desc");

            var masterData = await BasePageOutputExtensions.ToPagedListAsync(paData.ToList(), requestModel.Page, requestModel.PageSize);

            return resultMsg.SetResultMsg(
                 (int)ResultCode.Success,
                 HelperUtility.GetDescription(ResultCode.Success),
                 masterData);

        }

        [HttpPost("MasterDataSystemListNoPage")]
        public async Task<List<FrIpMasterDatum>> MasterDataSystemListNoPage()
        {
            return await _context.FrIpMasterData.Where(x => string.IsNullOrWhiteSpace(x.ParentCode) && x.Enable).ToListAsync();
        }

        [HttpPost("MasterDataListByOptionSetGroup")]
        public async Task<List<FrIpMasterDatum>> MasterDataListByOptionSetGroup(string optionSetGroup)
        {
            return await _context.FrIpMasterData.Where(x => x.OptionSetGroup == optionSetGroup && x.Enable && !string.IsNullOrEmpty(x.ParentCode)).ToListAsync();
        }

        [HttpPost("MasterDataList")]
        public async Task<ActionResult<ResultMsg>> MasterDataList(MasterDataListRequest requestModel)
        {
            var resultMsg = new ResultMsg();
            try
            {
                IQueryable<FrIpMasterDatum> paComont = _context.FrIpMasterData.Where(x=>!string.IsNullOrWhiteSpace(x.ParentCode)).AsQueryable();
                if (!string.IsNullOrWhiteSpace(requestModel.Enable))
                    paComont = paComont.Where(x => x.Enable.ToString() == requestModel.Enable);
                if (!string.IsNullOrWhiteSpace(requestModel.Code))
                    paComont = paComont.Where(x => x.Code.Contains(requestModel.Code));
                if (!string.IsNullOrWhiteSpace(requestModel.Name))
                    paComont = paComont.Where(x => x.Name.Contains(requestModel.Name));
                if (!string.IsNullOrWhiteSpace(requestModel.Value))
                    paComont = paComont.Where(x => x.Value.Contains(requestModel.Value));
                if (!string.IsNullOrWhiteSpace(requestModel.Description))
                    paComont = paComont.Where(x => x.Description.Contains(requestModel.Description));
                if (!string.IsNullOrEmpty(requestModel.OptionSetGroup))
                    paComont = paComont.Where(x => x.OptionSetGroup.Contains(requestModel.OptionSetGroup));

                var paData = paComont.ToList().Select(x => new MasterDataLisResponse()
                {
                    Id = x.Id,
                    Code = x.Code,
                    Name = x.Name,
                    Value = x.Value,
                    Description = x.Description,
                    Enable = x.Enable,
                    OptionSetGroup = x.OptionSetGroup
                }).AsQueryable();

                if (!string.IsNullOrWhiteSpace(requestModel.Field) && paComont.Count() > 0)
                    paData = DBHelper.DataSorting(paData, requestModel.Field, requestModel.Order);
                else
                    paData = DBHelper.DataSorting(paData, "CreateDate", "desc");

                var masterData = await BasePageOutputExtensions.ToPagedListAsync(paData.ToList(), requestModel.Page, requestModel.PageSize);

                return resultMsg.SetResultMsg(
                     (int)ResultCode.Success,
                     HelperUtility.GetDescription(ResultCode.Success),
                     masterData);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return resultMsg.SetResultMsg(
                     (int)ResultCode.ErrorOnRequestUnMarshalling,
                     HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                     null);
            }
        }

        [HttpGet("{id}")]
        public async Task<ActionResult<ResultMsg>> MasterDataDetail(Guid id)
        {
            var resultMsg = new ResultMsg();
            var dataDictionary = await _context.FrIpMasterData.FindAsync(id);

            if (dataDictionary == null)
            {
                return resultMsg.SetResultMsg(
                (int)ResultCode.NoDataFound,
                HelperUtility.GetDescription(ResultCode.NoDataFound),
                null);
            }

            return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                new MasterDataLisResponse()
                {
                    Id = dataDictionary.Id,
                    Code = dataDictionary.Code,
                    Name = dataDictionary.Name,
                    Value = dataDictionary.Value,
                    Enable = dataDictionary.Enable,
                    Description = dataDictionary.Description,
                    OptionSetGroup = dataDictionary.OptionSetGroup
                });
        }


        [Log("MasterData", "InsertMasterData", description: "MasterData/InsertMasterData", LogType: Enums.LogType.AdministratorAccountLog)]
        [HttpPost("InsertMasterData")]
        public async Task<ActionResult<ResultMsg>> InsertMasterData([FromBody] InsertMasterDataRequest requestModel)
        {
            var resultMsg = new ResultMsg();
            try
            {
                if (MasterDataExists(requestModel.Code, requestModel.OptionSetGroup, requestModel.ParentCode))
                {
                    return resultMsg.SetResultMsg(
                   (int)ResultCode.DataAlreadyExists,
                   HelperUtility.GetDescription(ResultCode.DataAlreadyExists),
                   null);
                }
                FrIpMasterDatum masterData = new FrIpMasterDatum();
                masterData.Id = Guid.NewGuid();
                masterData.Code = requestModel.Code;
                masterData.Name = requestModel.Name;
                masterData.Value = requestModel.Value;
                masterData.OptionSetGroup = requestModel.OptionSetGroup;
                masterData.ParentCode = requestModel.ParentCode;
                masterData.Description = requestModel.Description;
                masterData.Enable = requestModel.Enable;
                masterData.CreateDate = DateTime.Now;
                masterData.UpdateDate = DateTime.Now;
                masterData.CreateUser = CurrentUserId;
                masterData.UpdateUser = CurrentUserId;
                _context.Entry(masterData).State = EntityState.Added;
                await _context.SaveChangesAsync();

                return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                null);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return resultMsg.SetResultMsg(
                 (int)ResultCode.ErrorOnRequestUnMarshalling,
                 HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                 null);
            }
        }

        [HttpPost("MasterDataTree")]
        public async Task<ActionResult<ResultMsg>> MasterDataTree()
        {
            var resultMsg = new ResultMsg();
            try
            {
                var list = await _context.FrIpMasterData.Where(x => x.Enable)
                    .Select(x => new MasterDataTreeOutput()
                    {
                        Id = x.Id,
                        Code = x.Code,
                        ParentCode = x.ParentCode
                    }).ToListAsync();

                List<MasterDataTreeOutput> menus = new List<MasterDataTreeOutput>();
                var menu = list.Where(x => string.IsNullOrWhiteSpace(x.ParentCode)).Select(x => new MasterDataTreeOutput
                {
                    Id = x.Id,
                    Code = x.Code,
                    ParentCode = x.ParentCode,
                }).ToList();

                GetMasterDateTree(menu, list);

                return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                menu);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return resultMsg.SetResultMsg(
                 (int)ResultCode.ErrorOnRequestUnMarshalling,
                 HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                 null);
            }
        }


        [NonAction]
        private void GetMasterDateTree(List<MasterDataTreeOutput> menus, List<MasterDataTreeOutput> list)
        {
            foreach (var item in menus)
            {
                var _list = list.Where(s => s.ParentCode == item.Code).Select(m => new MasterDataTreeOutput
                {
                    Id = m.Id,
                    Code = m.Code,
                    ParentCode = m.ParentCode
                }).ToList();

                if (_list != null)
                {
                    item.childList.AddRange(_list.OrderBy(x => x.Code));
                    GetMasterDateTree(_list, list);
                }
            }
        }


        [Log("MasterData", "UpdateMasterData", description: "MasterData/UpdateMasterData", LogType: Enums.LogType.AdministratorAccountLog)]
        [HttpPost("UpdateMasterData")]
        public async Task<ActionResult<ResultMsg>> UpdateMasterData([FromBody] UpdateMasterDataRequest requestModel)
        {
            var resultMsg = new ResultMsg();
            try
            {
                var masterData = await _context.FrIpMasterData.FirstOrDefaultAsync(x => x.Id == requestModel.Id);
                if (masterData == null)
                    return resultMsg.SetResultMsg((int)ResultCode.NoDataFound, HelperUtility.GetDescription(ResultCode.NoDataFound), null);

                if (!masterData.Code.Equals(requestModel.Code) && MasterDataExists(requestModel.Code, requestModel.OptionSetGroup, requestModel.OptionSetGroup))
                {
                    return resultMsg.SetResultMsg(
                   (int)ResultCode.DataAlreadyExists,
                   HelperUtility.GetDescription(ResultCode.DataAlreadyExists),
                   null);
                }

                masterData.Name = requestModel.Name;
                masterData.Value = requestModel.Value;
                masterData.ParentCode = requestModel.ParentCode;
                masterData.Enable = requestModel.Enable;
                masterData.Description = requestModel.Description;
                masterData.UpdateDate = DateTime.Now;
                masterData.UpdateUser = CurrentUserId;
                _context.Entry(masterData).State = EntityState.Modified;
                await _context.SaveChangesAsync();
                return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                null);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return resultMsg.SetResultMsg(
                 (int)ResultCode.ErrorOnRequestUnMarshalling,
                 HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                 null);
            }
        }

        [Log("MasterData", "EnableMasterData", description: "MasterData/EnableMasterData", LogType: Enums.LogType.AdministratorAccountLog)]
        [HttpPut("EnableMasterData")]
        public async Task<ActionResult<ResultMsg>> EnableMasterData([FromBody] EnableMasterDataRequest requestModel)
        {
            ResultMsg resultMsg = new();
            requestModel.ids = "," + requestModel.ids + ",";
            var masterDataList = _context.FrIpMasterData.Where(x => requestModel.ids.Contains("," + x.Id.ToString() + ",")).ToList();
            if (masterDataList == null || masterDataList.Count <= 0)
            {
                return resultMsg.SetResultMsg(
               (int)ResultCode.NoDataFound,
               HelperUtility.GetDescription(ResultCode.NoDataFound),
               null);
            }
            foreach (var masterData in masterDataList)
            {
                masterData.Enable = requestModel.enable;
            }
            await _context.SaveChangesAsync();
            return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                null);
        }

        [NonAction]
        public bool MasterDataExists(string code, string optionSetGroup, string parentCode = "")
        {
            if (!string.IsNullOrWhiteSpace(parentCode))
            {
                return _context.FrIpMasterData.Any(x => x.Code == code && !string.IsNullOrWhiteSpace(x.ParentCode));
            }
            else { 
                return _context.FrIpMasterData.Any(x => x.OptionSetGroup == optionSetGroup && string.IsNullOrWhiteSpace(x.ParentCode));
            }
        }
    }
}
